#pragma once
#ifndef OBR_PROGRAMENTRY_H
#define OBR_PROGRAMENTRY_H

#include "CudaBuffer.h"
#include "CudaModule.h"
#include "CudaProgram.h"
#include "common.h"

namespace OBR
{
class ProgramEntry
{
protected:
    CudaBuffer sbt_data;

public:
    std::shared_ptr<CudaModule> cuda_module;
    OptixProgramGroupOptions program_opt;
    OptixProgramGroupDesc program_desc;

public:
    ProgramEntry(std::string _cuda_source_path);
    ~ProgramEntry();

    /**
     * @brief Get the Program of this type
     *
     * @return std::shared_ptr<CudaProgram>
     */
    virtual std::shared_ptr<CudaProgram> getProgram() = 0;

    /**
     * @brief upload sbt data to cuda buffer (not all programs use this entry)
     *
     */
    virtual void uploadSbtData();

    /**
     * @brief update sbt data to cuda buffer (not all programs use this entry)
     *
     */
    virtual void updateSbtData();

    /**
     * @brief Get the device ptr to sbt data
     *
     * @return CUdeviceptr
     */
    virtual CUdeviceptr getSbtDevicePtr();

    /**
     * @brief create program and link to this class
     *
     */
    void linkProgram(OptixDeviceContext &ctx,
                     OptixPipelineCompileOptions &pipeline_compile_options);

private:
    /**
     * @brief Get the Program Group Options of this type
     *
     * @return OptixProgramGroupOptions&
     */
    virtual OptixProgramGroupOptions &getProgramGroupOptions() = 0;

    /**
     * @brief Get the Program Group Desc of this type
     *
     * @return OptixProgramGroupOptions&
     */
    virtual OptixProgramGroupDesc &getProgramGroupDesc() = 0;

    /**
     * @brief Set the Program for this type
     *
     * @param prog std::shared_ptr<CudaProgram>
     */
    virtual void setProgram(std::shared_ptr<CudaProgram> prog) = 0;
};

} // namespace OBR

#endif
